package com.wang.common.dao.impl;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.wang.common.dao.IBaseDao;
import com.wang.common.util.DbUtil;
import com.wang.common.util.PageInfoUtil;

/**
 * 所有dao实现类里面公共的代码
 * 	孝子:实现所有的抽象方法
 * 	不孝子:我也是抽象的
 * @author Zjx
 *
 * @param <T>
 */
public abstract class BaseDaoImpl<T> implements IBaseDao<T>
{
	/**
	 * 执行sql语句
	 * @param sql	sql语句
	 * @param paramsList
	 * @return
	 */
	protected int executeSql(String sql,List<Object> paramsList)
	{
		System.out.println("sql===" + sql);
		System.out.println("paramsList==" + paramsList);
		int res = 0 ; 
		/* 标准的jdbc */
		DbUtil dbUtil = DbUtil.getInstance();
		/* 获取链接 */
		Connection connection = dbUtil.getConnection();
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			/* 获取sql语句 */
			ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			res = ps.executeUpdate();
			/* 取主键 */
			rs = ps.getGeneratedKeys();
			if(rs.next())
			{
				int id = rs.getInt(1);
				/* List最后一个是主键 */
				paramsList.add(id);
			}
			return res ; 
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(connection, ps, rs);
		}
		return res ; 
	}
	
	/**
	 * 查询多条记录;不分页
	 * @param sql	sql语句
	 * @param paramsList	条件
	 * @return
	 */
	protected List<T> findListSql(PageInfoUtil pageInfoUtil,String sql,List<Object> paramsList,Class cla)
	{
		//System.out.println("sql===" + sql);
		//System.out.println("paramsList==" + paramsList);
		List<T> resultList = new ArrayList<T>();
		/* 标准的jdbc */
		DbUtil dbUtil = DbUtil.getInstance();
		/* 获取链接 */
		Connection connection = dbUtil.getConnection();
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			/*=====计算总条数=====*/
			String countSql = "select count(*) " + sql.substring(sql.indexOf("from"), sql.length());
			System.out.println("=sql===>" + countSql);
			System.out.println("=参数===>" + paramsList);
			/* 获取sql语句 */
			ps = connection.prepareStatement(countSql,Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			if(rs.next())
			{
				int totalRecord = rs.getInt(1);
				pageInfoUtil.setTotalRecord(totalRecord);
			}
			
			rs.close();
			ps.close();
			
			//sql.append(" limit ?,?");
			sql = sql + " limit ?,? " ; 
			paramsList.add(pageInfoUtil.getCurrentRecord());
			paramsList.add(pageInfoUtil.getPageSize());
			
			
			System.out.println("=sql===>" + sql);
			System.out.println("=参数===>" + paramsList);
			/* 获取sql语句 */
			ps = connection.prepareStatement(sql.toString(),Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			while(rs.next())
			{
				T role = this.converFromRs(rs,cla);
				resultList.add(role);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(connection, ps, rs);
		}
		return resultList; 
	}
	protected List<Map<String,Object>> findListMapSql(PageInfoUtil pageInfoUtil,String sql,List<Object> paramsList)
	{
		//System.out.println("sql===" + sql);
		//System.out.println("paramsList==" + paramsList);
		List<Map<String,Object>> resultList = new ArrayList<Map<String,Object>>();
		/* 标准的jdbc */
		DbUtil dbUtil = DbUtil.getInstance();
		/* 获取链接 */
		Connection connection = dbUtil.getConnection();
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			/*=====计算总条数=====*/
			String countSql = "select count(*) from (" + sql + ") t ";
			System.out.println("=sql===>" + countSql);
			System.out.println("=参数===>" + paramsList);
			/* 获取sql语句 */
			ps = connection.prepareStatement(countSql,Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			if(rs.next())
			{
				int totalRecord = rs.getInt(1);
				pageInfoUtil.setTotalRecord(totalRecord);
			}
			
			rs.close();
			ps.close();
			
			//sql.append(" limit ?,?");
			sql = sql + " limit ?,? " ; 
			paramsList.add(pageInfoUtil.getCurrentRecord());
			paramsList.add(pageInfoUtil.getPageSize());
			
			
			System.out.println("=sql===>" + sql);
			System.out.println("=参数===>" + paramsList);
			/* 获取sql语句 */
			ps = connection.prepareStatement(sql.toString(),Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			while(rs.next())
			{
				Map<String,Object> dataTempMap = new HashMap<String, Object>();
				/* 拿着rs获取sql语句执行的所有列名
				 * 结果集的元素数据
				 *  */
				ResultSetMetaData metaData = rs.getMetaData();
				//System.out.println("==metaData.getColumnCount()==" + metaData.getColumnCount());
				int totalColumnCount = metaData.getColumnCount() ;
				for(int i = 1 ; i <= totalColumnCount ; i ++ )
				{
					/* 列的名称取出来,======pojo的属性取出来了 */
					String columnName = metaData.getColumnName(i);
					/* i:就是第几列
					 * 别名:columnLabel而不是columnName
					 *  */
					Object objVal = rs.getObject(i);
					/* 键是列的别名,值是列对应的值 */
					dataTempMap.put(columnName, objVal);
				}
				
				
				resultList.add(dataTempMap);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(connection, ps, rs);
		}
		return resultList; 
	}
	
	
	protected List<Map<String,Object>> findListMapSql(String sql,List<Object> paramsList)
	{
		//System.out.println("sql===" + sql);
		//System.out.println("paramsList==" + paramsList);
		List<Map<String,Object>> resultList = new ArrayList<Map<String,Object>>();
		/* 标准的jdbc */
		DbUtil dbUtil = DbUtil.getInstance();
		/* 获取链接 */
		Connection connection = dbUtil.getConnection();
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			
			/* 获取sql语句 */
			ps = connection.prepareStatement(sql.toString(),Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			while(rs.next())
			{
				Map<String,Object> dataTempMap = new HashMap<String, Object>();
				/* 拿着rs获取sql语句执行的所有列名
				 * 结果集的元素数据
				 *  */
				ResultSetMetaData metaData = rs.getMetaData();
				//System.out.println("==metaData.getColumnCount()==" + metaData.getColumnCount());
				int totalColumnCount = metaData.getColumnCount() ;
				for(int i = 1 ; i <= totalColumnCount ; i ++ )
				{
					/* 列的名称取出来,======pojo的属性取出来了 */
					String columnName = metaData.getColumnName(i);
					/* i:就是第几列
					 * 别名:columnLabel而不是columnName
					 *  */
					Object objVal = rs.getObject(i);
					/* 键是列的别名,值是列对应的值 */
					dataTempMap.put(columnName, objVal);
				}
				
				
				resultList.add(dataTempMap);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(connection, ps, rs);
		}
		return resultList; 
	}
	
	/**
	 * 查询多条记录;不分页
	 * @param sql	sql语句
	 * @param paramsList	条件
	 * @return
	 */
	protected List<T> findListSql(String sql,List<Object> paramsList,Class cla)
	{
		//System.out.println("sql===" + sql);
		//System.out.println("paramsList==" + paramsList);
		List<T> resultList = new ArrayList<T>();
		/* 标准的jdbc */
		DbUtil dbUtil = DbUtil.getInstance();
		/* 获取链接 */
		Connection connection = dbUtil.getConnection();
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			//System.out.println("=sql===>" + sql);
			//System.out.println("=参数===>" + paramsList);
			/* 获取sql语句 */
			ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			while(rs.next())
			{
				T t = this.converFromRs(rs,cla);
				
				resultList.add(t);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(connection, ps, rs);
		}
		return resultList; 
	}
	
	/**
	 * 执行sql语句查询一条结果
	 * @param sql	sql语句
	 * @param paramsList	条件
	 * @return
	 */
	protected T findOneSql(String sql, List<Object> paramsList,Class cla)
	{
		//System.out.println("sql===" + sql);
		//System.out.println("paramsList==" + paramsList);
		/* 标准的jdbc */
		DbUtil dbUtil = DbUtil.getInstance();
		/* 获取链接 */
		Connection connection = dbUtil.getConnection();
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			/* 获取sql语句 */
			ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			if(rs.next())
			{
				T t = converFromRs(rs,cla);
				return t ; 
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(connection, ps, rs);
		}
		return null ; 
	}
	
	/**
	 * 数据库里面的数据转换成一个pojo
	 * @param rs	resultSet:结果集
	 * @return	返回一个pojo
	 * @throws SQLException
	 */
	//protected abstract T converFromRs(ResultSet rs) throws SQLException ;
	
	
	/**
	 * 老做法:
	 * 	使用反射:获取pojo的所有属性;
	 * 	拿着属性名调用rs.getObject(属性名);属性名和列名一样
	 *  找set方法;set+属性名首字母大写+属性的剩余部分;如属性名叫name;set方法就是setName;
	 *  由于在一个类里面方法名重复的很多(重载),要想确定某一个方法得加上参数类型,确定一个方法
	 *  调用方法:对象名.方法;method.invoke(参数1:对象,参数2:实参);set方法木有返回值
	 *  要去除以Obj结尾和Str结尾的
	 *  
	 *  新做法:
	 *  	拿着rs获取sql语句执行的所有列名
	 *  	取出列名对应的值
	 *  	使用反射,创建出一个对象
	 *  	使用反射找到set+列名的method;
	 *  	调用method方法(set方法)
	 *  
	 *  T:是一个Object类型的对象
	 */
	protected T converFromRs(ResultSet rs,Class cla) throws SQLException
	{
		//System.out.println("AAdmins==converFromRs===");
		/* Class对象 */
		Object t = null ;
		try
		{
			t = cla.getDeclaredConstructor().newInstance();
		} catch (Exception e)
		{
			e.printStackTrace();
		}
		/* 拿着rs获取sql语句执行的所有列名
		 * 结果集的元素数据
		 *  */
		ResultSetMetaData metaData = rs.getMetaData();
		//System.out.println("==metaData.getColumnCount()==" + metaData.getColumnCount());
		int totalColumnCount = metaData.getColumnCount() ;
		for(int i = 1 ; i <= totalColumnCount ; i ++ )
		{
			/* 列的类型:Integer(java的类型) */
//			String columnClassName = metaData.getColumnClassName(i);
//			/* label标签:别名;id: */
//			String columnLabel = metaData.getColumnLabel(i);
//			/* 列的名字 */
//			String columnName = metaData.getColumnName(i);
//			/* 整数:4; */
//			int columnType = metaData.getColumnType(i);
//			/* 数据库的类型 */
//			String columnTypeName = metaData.getColumnTypeName(i);
//			System.out.println(i + "==columnClassName:" + columnClassName + "===columnLabel:" + columnLabel
//					+ "===columnName:" +  columnName + "==columnType:" + columnType
//					+ "===columnTypeName:" + columnTypeName);
			
			/* 列的名称取出来,======pojo的属性取出来了 */
			String columnName = metaData.getColumnName(i);
			/* i:就是第几列
			 * 别名:columnLabel而不是columnName
			 *  */
			Object objVal = rs.getObject(i);
			String columnClassName = metaData.getColumnClassName(i);
			/* 取出一个set方法
			 * 如列的名称是id;set方法的名称就是setId
			 *  */
			String methodName = "set" + columnName.substring(0, 1).toUpperCase() + columnName.substring(1,columnName.length());
			try
			{
				/* 获取Class */
				Class columnClass = Class.forName(columnClassName);
				
				while(true)
				{
					try
					{
						findMethod(cla, t, objVal, methodName, columnClass);
						break ; 
					} catch (Exception e)
					{
						// 如果发现问题,此处的异常得放开
						//e.printStackTrace();
					}
					
					/* 谁让pojo的属性类型和数据库的类型不一致呢?
					 * 为啥createTime在数据库中创建的时候是Datetime类型但是在获取的是timestamp类型
					 *  */
					/* 加上各种判断 */
					if(columnClass == Integer.class)
					{
						columnClass = int.class; 
					}else if(columnClass == int.class)
					{
						columnClass = byte.class; 
						/* objVal===Integer
						 * objval==Integer变成了byte
						 * 再把byte赋值给objval(重新赋值了);它本身是byte,只不过看成了object
						 *  */
						byte byteVal = Byte.valueOf(objVal + "") ; 
						objVal = byteVal ; 
					}else if(columnClass == Timestamp.class)
					{
						columnClass = Date.class ; 
					}else
					{
						/* 把所有的类型都试了一遍,还是不行;就认为赋值失败 */
						break ; 
					}
				}
			}catch (Exception e)
			{
				e.printStackTrace();
			}
		}
		return (T) t;
	}

	/**
	 * 专门为method赋值
	 * @param cla
	 * @param t
	 * @param objVal
	 * @param methodName
	 * @param columnClass
	 * @throws NoSuchMethodException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	private void findMethod(Class cla, Object t, Object objVal, String methodName, Class columnClass)
			throws Exception
	{
		/* 参数1:方法名,参数2:形参的类型
		 * public void setId(int id)
		 *  */
		Method method = cla.getMethod(methodName, columnClass);
		/* 调用方法
		 * 对象名.方法(实参);
		 * 
		 * 参数1:对象
		 * 参数2:实参
		 *  */
		method.invoke(t, objVal);
	}
	
	/**
	 * 查询多条记录;不分页
	 * @param sql	sql语句
	 * @param paramsList	条件
	 * @return	List每一个元素就是一条记录;map的键就是列的别名，值：值;
	 * Map---->pojo
	 * List<Map>====List<Pojo>
	 * List<Map>====List<AAdmins>
	 * map的键===pojo的属性名;map的值===pojo的属性值
	 * 我们为什么不用pojo,因为sql语句查询出的列无法对应到某个pojo的属性;如totalCount
	 */
	protected List<Map<String, Object>> findListSql(String sql,List<Object> paramsList)
	{
		//System.out.println("sql===" + sql);
		//System.out.println("paramsList==" + paramsList);
		List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
		/* 标准的jdbc */
		DbUtil dbUtil = DbUtil.getInstance();
		/* 获取链接 */
		Connection connection = dbUtil.getConnection();
		PreparedStatement ps = null ; 
		ResultSet rs = null ; 
		try
		{
			//System.out.println("=sql===>" + sql);
			//System.out.println("=参数===>" + paramsList);
			/* 获取sql语句 */
			ps = connection.prepareStatement(sql,Statement.RETURN_GENERATED_KEYS);
			/* 为占位符赋值 */
			for(int i = 0 ; i < paramsList.size() ; i ++)
			{
				ps.setObject(i + 1 , paramsList.get(i));
			}
			/* 执行sql语句 */
			rs = ps.executeQuery();
			while(rs.next())
			{
				Map<String,Object> dataTempMap = new HashMap<String, Object>();
				/* 拿着rs获取sql语句执行的所有列名
				 * 结果集的元素数据
				 *  */
				ResultSetMetaData metaData = rs.getMetaData();
				//System.out.println("==metaData.getColumnCount()==" + metaData.getColumnCount());
				int totalColumnCount = metaData.getColumnCount() ;
				for(int i = 1 ; i <= totalColumnCount ; i ++ )
				{
					/* 列的名称取出来,======pojo的属性取出来了 */
					String columnName = metaData.getColumnName(i);
					/* i:就是第几列
					 * 别名:columnLabel而不是columnName
					 *  */
					Object objVal = rs.getObject(i);
					/* 键是列的别名,值是列对应的值 */
					dataTempMap.put(columnName, objVal);
				}
				
				
				resultList.add(dataTempMap);
			}
		} catch (SQLException e)
		{
			e.printStackTrace();
		} finally
		{
			dbUtil.closeAll(connection, ps, rs);
		}
		return resultList; 
	}

}
